home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Personal Computer World 2005 October
/
PCWOCT05.iso
/
Software
/
FromTheMag
/
XAMPP 1.4.14
/
xampp-win32-1.4.14-installer.exe
/
xampp
/
php
/
pear
/
Net
/
NNTP.php
< prev
next >
Wrap
PHP Script
|
2004-10-01
|
21KB
|
710 lines
<?php
//
// +----------------------------------------------------------------------+
// | PHP Version 4 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2003 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.0 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available at through the world-wide-web at |
// | http://www.php.net/license/2_02.txt. |
// | If you did not receive a copy of the PHP license and are unable to |
// | obtain it through the world-wide-web, please send a note to |
// | license@php.net so we can mail you a copy immediately. |
// +----------------------------------------------------------------------+
// | Authors: Martin Kaltoft <martin@nitro.dk> |
// | Tomas V.V.Cox <cox@idecnet.com> |
// | Heino H. Gehlsen <heino@gehlsen.dk> |
// +----------------------------------------------------------------------+
//
// $Id: NNTP.php,v 1.15.2.4 2004/03/10 08:47:13 heino Exp $
require_once 'PEAR.php';
// Deprecated due to naming
define('PEAR_NNTP_ALL', 0);
define('PEAR_NNTP_NAMES', 1);
define('PEAR_NNTP_LIST', 2);
/* NNTP Authentication modes */
define('NET_NNTP_AUTHORIGINAL', 'original');
define('NET_NNTP_AUTHSIMPLE', 'simple');
define('NET_NNTP_AUTHGENERIC', 'generic');
// Deprecated due to naming
define('PEAR_NNTP_AUTHORIGINAL', NET_NNTP_AUTHORIGINAL);
define('PEAR_NNTP_AUTHSIMPLE', NET_NNTP_AUTHSIMPLE);
define('PEAR_NNTP_AUTHGENERIC', NET_NNTP_AUTHGENERIC);
/**
* The NNTP:: class fetches UseNet news articles acording to the standard
* based on RFC 1036.
*
* @version 0.2.2
* @author Martin Kaltoft <martin@nitro.dk>
* @author Tomas V.V.Cox <cox@idecnet.com>
* @author Heino H. Gehlsen <heino@gehlsen.dk>
*/
class Net_NNTP extends PEAR
{
var $max = '';
var $min = '';
var $user = null;
var $pass = null;
var $authmode = null;
/** File pointer of the nntp-connection */
var $fp = null;
/**
* Connect to the newsserver
*
* @param string $nntpserver The adress of the NNTP-server to connect to.
* @param int $port (optional) the port-number to connect to, defaults to 119.
* @param string $user (optional) The user name to authenticate with
* @param string $pass (optional) The password
* @param string $authmode (optional) The authentication mode
* @return mixed True on success or Pear Error object on failure
* @see Net_Nntp::authenticate()
* @access public
*/
function connect($nntpserver,
$port = 119,
$user = null,
$pass = null,
$authmode = NET_NNTP_AUTHORIGINAL)
{
$fp = @fsockopen($nntpserver, $port, $errno, $errstr, 15);
if (!is_resource($fp)) {
return $this->raiseError("Could not connect to NNTP-server $nntpserver");
}
socket_set_blocking($fp, true);
if (!$fp) {
return $this->raiseError('Not connected');
}
$response = fgets($fp, 256);
if ($this->_debug) {
print "<< $response\n";
}
$this->fp = $fp;
$this->user = $user;
$this->pass = $pass;
$this->authmode = $authmode;
return true;
}
/**
* Connect to the newsserver, and issue a GROUP command
* Once connection is prepared, we can only fetch articles from one group
* at a time, to fetch from another group, a new connection has to be made.
*
* This is to avoid the GROUP command for every article, as it is very
* ressource intensive on the newsserver especially when used for
* groups with many articles.
*
* @param string $nntpserver The adress of the NNTP-server to connect to.
* @param int $port (optional) the port-number to connect to, defaults to 119.
* @param string $newsgroup The name of the newsgroup to use.
* @param string $user (optional) The user name to authenticate with
* @param string $pass (optional) The password
* @param string $authmode (optional) The authentication mode
* @return mixed True on success or Pear Error object on failure
* @see Net_Nntp::authenticate()
* @access public
* @deprecated Use connect() instead
*/
function prepareConnection($nntpserver,
$port = 119,
$newsgroup,
$user = null,
$pass = null,
$authmode = NET_NNTP_AUTHORIGINAL)
{
/* connect to the server */
$err = $this->connect($nntpserver, $port, $user, $pass, $authmode);
if (PEAR::isError($err)) {
return $err;
}
/* issue a GROUP command */
$r = $this->command("GROUP $newsgroup");
if (PEAR::isError($r) || $this->responseCode($r) > 299) {
return $this->raiseError($r);
}
$response_arr = split(' ', $r);
$this->max = $response_arr[3];
$this->min = $response_arr[2];
return true;
}
/**
* @deprecated
*/
function prepare_connection($nntpserver,
$port = 119,
$newsgroup,
$user = null,
$pass = null,
$authmode = NET_NNTP_AUTHORIGINAL)
{
return $this->prepareConnection($nntpserver, $port, $newsgroup, $user, $pass, $authmode);
}
/**
* Auth process (not yet standarized but used any way)
* http://www.mibsoftware.com/userkt/nntpext/index.html
*
* @param string $user The user name
* @param string $pass (optional) The password if needed
* @param string $mode Authinfo form: original, simple, generic
* @return mixed (bool) true on success or Pear Error obj on fail
* @access public
*/
function authenticate($user = null, $pass = null, $mode = NET_NNTP_AUTHORIGINAL)
{
if ($user === null) {
return $this->raiseError('Authentication required but no user supplied');
}
switch ($mode) {
case NET_NNTP_AUTHORIGINAL:
/*
281 Authentication accepted
381 More authentication information required
480 Authentication required
482 Authentication rejected
502 No permission
*/
$response = $this->command("AUTHINFO user $user", false);
if ($this->responseCode($response) != 281) {
if ($this->responseCode($response) == 381 && $pass !== null) {
$response = $this->command("AUTHINFO pass $pass", false);
}
}
if ($this->responseCode($response) != 281) {
return $this->raiseError("Authentication failed: $response");
}
return true;
break;
case NET_NNTP_AUTHSIMPLE:
case NET_NNTP_AUTHGENERIC:
default:
$this->raiseError("The auth mode: $mode isn't implemented");
}
}
/**
* Get an article from the currently open connection.
* To get articles from another newsgroup a new prepare_connection() -
* call has to be made with apropriate parameters
*
* @param mixed $article Either the message-id or the message-number on the server of the article to fetch
* @return string the article
* @access public
*/
function getArticle($article)
{
/* tell the newsserver we want an article */
$r = $this->command("ARTICLE $article");
if (PEAR::isError($r) || $this->responseCode($r) > 299) {
return $this->raiseError($r);
}
$post = null;
while (!feof($this->fp)) {
$line = rtrim(fgets($this->fp, 256), "\r\n");
if ($line == ".") {
break;
} else {
$post .= $line ."\n";
}
}
return $post;
}
/**
* @deprecated
*/
function get_article($article)
{
return $this->getArticle($article);
}
/**
* Post an article to a newsgroup.
* Among the aditional headers you might think of adding could be:
* "NNTP-Posting-Host: <ip-of-author>", which should contain the IP-adress
* of the author of the post, so the message can be traced back to him.
* Or "Organization: <org>" which contain the name of the organization
* the post originates from.
*
* @param string $subject The subject of the post.
* @param string $newsgroup The newsgroup to post to.
* @param string $from Name + email-adress of sender.
* @param string $body The body of the post itself.
* @param string $aditionak (optional) Aditional headers to send.
* @return string server response
* @access public
*/
function post($subject, $newsgroup, $from, $body, $aditional = "")
{
if (!@is_resource($this->fp)) {
return $this->raiseError('Not connected');
}
/* tell the newsserver we want to post an article */
$r = $this->command('POST');
if (PEAR::isError($r) || $this->responseCode($r) != 340) {
return $this->raiseError($r);
}
$data = '';
$data .= "From: $from\r\n";
$data .= "Newsgroups: $newsgroup\r\n";
$data .= "Subject: $subject\r\n";
$data .= "X-poster: PEAR::Net_NNTP (0.2)\r\n";
if (!empty($aditional)) {
$data .= rtrim($aditional, "\r\n")."\r\n";
}
$data .= "\r\n";
$data .= "$body\r\n";
$data .= ".";
return $this->command($data, false);
}
/**
* Get the headers of an article from the currently open connection
* To get the headers of an article from another newsgroup, a new
* prepare_connection()-call has to be made with apropriate parameters
*
* @param string $article Either a message-id or a message-number of the article to fetch the headers from.
* @return array Header
* @access public
*/
function getHeaders($article)
{
/* tell the newsserver we want an article */
$r = $this->command("HEAD $article");
if (PEAR::isError($r) || $this->responseCode($r) > 299) {
return $this->raiseError($r);
}
$headers = '';
while(!feof($this->fp)) {
$line = rtrim(fgets($this->fp, 256), "\r\n");
if ($line == '.') {
break;
} else {
$headers .= $line . "\n";
}
}
return $headers;
}
/**
* @deprecated
*/
function get_headers($article)
{
return $this->getHeaders($article);
}
/**
* Returns the headers of a given article in the form of
* an associative array. Ex:
* array(
* 'From' => 'foo@bar.com (Foo Smith)',
* 'Subject' => 'Re: Using NNTP class',
* ....
* );
*
* @param $article string Article number or id
* @return array Assoc array with headers names as key or Pear obj error
* @access public
*/
function splitHeaders($article)
{
$headers = $this->get_headers($article);
if (PEAR::isError($headers)) {
return $headers;
}
$lines = explode("\n", $headers);
foreach ($lines as $line) {
$line = trim($line);
if (($pos = strpos($line, ':')) !== false) {
$head = substr($line, 0, $pos);
$ret[$head] = ltrim(substr($line, $pos+1));
// if the field was longer than 256 chars, look also in the next line
// XXX a better way to discover that than strpos?
} else {
$ret[$head] .= $line;
}
}
if (isset($ret['References']) &&
preg_match_all('|<.+>|U', $ret['References'], $matches))
{
$ret['References'] = $matches[0];
}
return $ret;
}
/**
* @deprecated
*/
function split_headers($article) {
return $this->splitHeaders($article);
}
/**
* Get the body of an article from the currently open connection.
* To get the body of an article from another newsgroup, a new
* prepare_connection()-call has to be made with apropriate parameters
*
* @param string $article Either a message-id or a message-number of the article to fetch the headers from.
* @access public
*/
function getBody($article)
{
/* tell the newsserver we want an article */
$r = $this->command("BODY $article");
if (PEAR::isError($r) || $this->responseCode($r) > 299) {
return $this->raiseError($r);
}
$body = null;
while (!feof($this->fp)) {
$line = rtrim(fgets($this->fp, 256), "\r\n");
if ($line == '.') {
break;
} else {
$body .= $line ."\n";
}
}
return $body;
}
/**
* @deprecated
*/
function get_body($article) {
return $this->getBody($article);
}
/**
* Get data until a line with only a '.' in it is read and return data.
*
* @return string data
* @access private
* @author Morgan Christiansson <mog@linux.nu>
*/
function _getData()
{
$body = array();
while(!feof($this->fp)) {
$line = rtrim(fgets($this->fp, 256), "\r\n");
if ($line == '.') {
break;
} else {
$body[] = $line;
}
}
return $body;
}
/**
* @deprecated
*/
function get_data() {
return $this->_getData();
}
/**
* Selects a news group (issue a GROUP command to the server)
*
* @param string $newsgroup The newsgroup name
* @return mixed Array on success or Pear Error object on failure
*/
function selectGroup($newsgroup)
{
$r = $this->command("GROUP $newsgroup");
if (PEAR::isError($r) || $this->responseCode($r) > 299) {
return $this->raiseError($r);
}
$response_arr = split(' ', $r);
$this->max = $response_arr[3];
$this->min = $response_arr[2];
return array(
"first" => $response_arr[2],
"last" => $response_arr[3]
);
}
/**
* @deprecated
*/
function select_group($newsgroup) {
return $this->selectGroup($newsgroup);
}
/**
* Fetches a list of all avaible newsgroups
*
* @param int $fetch PEAR_NNTP_ALL PEAR_NNTP_NAMES PEAR_NNTP_LIST
* @return array nested array with informations about
* existing newsgroups
* @author Morgan Christiansson <mog@linux.nu>
*/
function getGroups($fetch = true)
{
$this->command("LIST");
foreach($this->_getData() as $line) {
$arr = explode(" ",$line);
$groups[$arr[0]]["group"] = $arr[0];
$groups[$arr[0]]["last"] = $arr[1];
$groups[$arr[0]]["first"] = $arr[2];
$groups[$arr[0]]["posting_allowed"] = $arr[3];
}
$this->command("LIST NEWSGROUPS");
foreach($this->_getData() as $line) {
preg_match("/^(.*?)\s(.*?$)/",$line,$matches);
$groups[$matches[1]]["desc"] = $matches[2];
}
return $groups;
}
/**
* @deprecated
*/
function get_groups($fetch=true) {
return $this->getGroups($fetch);
}
/**
* Returns a list of avaible headers
* which are send from newsserver to client
* for every news message
*
* @return array header names
* @access public
*/
function getOverviewFmt()
{
$this->command("LIST OVERVIEW.FMT");
$format = array("number");
// XXX Use the splitHeaders() algorithm for supporting
// multiline headers?
foreach ($body = $this->_getData() as $line) {
$line = current(explode(":",$line));
$format[] = $line;
}
return $format;
}
/**
* @deprecated
*/
function get_overview_fmt() {
return $this->getOverviewFmt();
}
/**
* Fetch message header
* from message number $first until $last
*
* The format of the returned array is:
* $messages[message_id][header_name]
*
* @param integer $first first article to fetch
* @param integer $last last article to fetch
* @return array nested array of message and
* there headers
* @access public
*/
function getOverview($first,$last) {
$format = $this->getOverviewFmt();
$this->command("XOVER $first-$last");
foreach($this->_getData() as $line) {
$i=0;
foreach(explode("\t",$line) as $line) {
$message[$format[$i++]] = $line;
}
$messages[$message["Message-ID"]] = $message;
}
return $messages;
}
/**
* @deprecated
*/
function get_overview($first,$last) {
return $this->getOverview($first, $last);
}
/**
* Get the date from the newsserver
* format of returned date:
* $date['y'] - year
* $date['m'] - month
* $date['d'] - day
*
* @return array date
* @access public
*/
function date()
{
$r = $this->command('DATE');
if (PEAR::isError($r) || $this->responseCode($r) > 299) {
return $this->raiseError($r);
}
$data = explode(' ',$r);
$date['y']=substr($data[1],0,4);
$date['m']=substr($data[1],4,2);
$date['d']=substr($data[1],6,2);
return $date;
}
/**
* Maximum article number in current group
*
* @return integer maximum
* @access public
*/
function max()
{
if (!@is_resource($this->fp)) {
return $this->raiseError('Not connected');
}
return $this->max;
}
/**
* Minimum article number in current group
*
* @return integer minimum
* @access public
*/
function min()
{
if (!@is_resource($this->fp)) {
return $this->raiseError('Not connected');
}
return $this->min;
}
/**
* Test whether we are connected or not.
*
* @return bool true or false
* @access public
*/
function isConnected()
{
if (@is_resource($this->fp)) {
return true;
}
return false;
}
/**
* @deprecated
*/
function is_connected() {
return $this->isConnected();
}
/**
* Close connection to the newsserver
*
* @access public
*/
function quit()
{
$this->command("QUIT");
fclose($this->fp);
}
/**
* returns the response code
* of a newsserver command
*
* @param string $response newsserver answer
* @return integer response code
* @access public
*/
function responseCode($response)
{
$parts = explode(' ', ltrim($response));
return (int) $parts[0];
}
/**
* sets debug on or off
*
* @param boolean $on true=on, false=off
* @access public
*/
function setDebug($on = true)
{
$this->_debug = $on;
}
/**
* @deprecated
*/
function set_debug($on = true) {
return $this->setDebug();
}
/**
* Issue a command to the NNTP server
*
* @param string $cmd The command to launch, ie: "ARTICLE 1004853"
* @param bool $testauth Test or not the auth
* @return mixed True on success or Pear Error object on failure
* @access public
*/
function command($cmd, $testauth = true)
{
if (!@is_resource($this->fp)) {
return $this->raiseError('Not connected');
}
fputs($this->fp, "$cmd\r\n");
if ($this->_debug) {
print ">> $cmd\n";
}
$response = fgets($this->fp, 128);
if ($this->_debug) {
print "<< $response\n";
}
// From the spec: "In all cases, clients must provide
// this information when requested by the server. Servers are
// not required to accept authentication information that is
// volunteered by the client"
$code = $this->responseCode($response);
if ($testauth && ($code == 450 || $code == 480)) {
$error = $this->authenticate($this->user, $this->pass, $this->authmode);
if (PEAR::isError($error)) {
return $error;
}
/* re-issue the command */
$response = $this->command($cmd, false);
}
return $response;
}
}
?>